package com.haoran.dwz.common.util;

import java.util.HashMap;
import java.util.Map;

public class DisorderedCompressEncoder {  
    final static char[] digits = {  
   		'0' , '1' , '2' , '3' , '4' , '5' ,  
        '6' , '7' , '8' , '9' , 'a' , 'b' ,  
        'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,  
        'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,  
        'o' , 'p' , 'q' , 'r' , 's' , 't' ,  
        'u' , 'v' , 'w' , 'x' , 'y' , 'z' ,  
        'A' , 'B' , 'C' , 'D' , 'E' , 'F' ,  
        'G' , 'H' , 'I' , 'J' , 'K' , 'L' ,  
        'M' , 'N' , 'O' , 'P' , 'Q' , 'R' ,  
        'S' , 'T' , 'U' , 'V' , 'W' , 'X' ,  
        'Y' , 'Z' , '+' , '-' ,  
        };  
    final static char[] disorderedDigits = {  
    		'c' , 'm' , 'v' , 'J' , 'X' , 'h' ,  
       		'0' , 'd' , '1' , '3' , 'y' , '5' ,  
       		'G' , 'H' , 'I' , 'f' , 'K' , 'C' ,  
       		'R' , 'e' , 'b' , 'x' , '4' , 'z' ,  
       		'o' , 'p' , 'q' , 'Q' , 's' , 'V' ,  
            '6' , 'O' , '8' , 'E' , 'a' , 'F' ,  
            'i' , 'j' , 'k' , 'l' , '2' , 'n' ,  
            'N' , 'B' , 'L' , 'D' , '9' , 'w' ,  
            'S' , 'T' , 'Z' , 't' , 'W' , 'g' ,  
            'M' , 'A' , '7' , 'P' , 'r' , 'u' ,  
            'Y' , 'U' , '+' , '-' ,  
            };
    
    final static Map<Character,Character> refMap =  new HashMap<>();
    
    final static Map<Character,Character> reverseRefMap =  new HashMap<>();
    
	static {
		if(disorderedDigits.length != digits.length)
			throw new IllegalArgumentException();
		for (int i = 0; i < digits.length; i++) {
			refMap.put(digits[i], disorderedDigits[i]);
		}
		
		for (int i = 0; i < digits.length; i++) {
			reverseRefMap.put(disorderedDigits[i], digits[i]);
		}
	}
    /** 
     * @param args 
     */  
    public static void main(String[] args) {  
    	System.out.println((int)'-');
    	System.out.println((int)'/');
//    1位 	[0,63]
//    2位 	[64,4095]
//    3位          [4096,262143]
//    4位	[262144,16777215]
//    5位	[16777216,1073741823]
    	System.out.println(compressNumber(64+1+1));
    	System.out.println(compressNumber(4095));
    	
    	System.out.println(compressNumber(4096+1+1));
    	System.out.println(compressNumber(262143));
    	
    	System.out.println(compressNumber(262144+1+1));
    	System.out.println(compressNumber(16777215));
    	
    	
    	System.out.println(compressNumber(16777216+1+1));
    	System.out.println(compressNumber(1073741823));
    	
    	System.out.println(unCompressNumber("c"));
        
    	System.out.println(unCompressNumber("-"));
        
        System.out.println(unCompressNumber(compressNumber(999999999999999999L)));  
    } 
    
    public static String compressNumber(long number) {
     
    	return compressNumber(number,6);
	}
    
    private static String compressNumber(long number, int shift) {  
        char[] buf = new char[64];  
        int charPos = 64;  
        int radix = 1 << shift;  
        long mask = radix - 1;  
        do {  
            buf[--charPos] = digits[(int)(number & mask)];  
            number >>>= shift;  
        } while (number != 0);  
        String compressNumber = new String(buf, charPos, (64 - charPos));
        StringBuilder sb = disorder(compressNumber);
        return sb.toString();  
    }

	private static StringBuilder disorder(String compressNumber) {
		StringBuilder sb = new StringBuilder();
        for (int i = 0; i < compressNumber.length(); i++)  {
        	Character character = refMap.get(compressNumber.charAt(i));
        	sb.append(character);
		}
		return sb;
	}  
	
	private static String reorder(String compressNumber) {
		StringBuilder sb = new StringBuilder();
        for (int i = 0; i < compressNumber.length(); i++)  {
        	Character character = reverseRefMap.get(compressNumber.charAt(i));
        	sb.append(character);
		}
		return sb.toString();
	}  
    
    /** 
     * 把64进制的字符串转换成10进制 
     * @param decompStr 
     * @return 
     */  
    
    public static long unCompressNumber(String decompStr)  
    {  
    	decompStr = reorder(decompStr);
        long result=0;  
        for (int i =  decompStr.length()-1; i >=0; i--) {  
            if(i==decompStr.length()-1)  
            {  
                result+=getCharIndexNum(decompStr.charAt(i));  
                continue;  
            }  
            for (int j = 0; j < digits.length; j++) {  
                if(decompStr.charAt(i)==digits[j])  
                {  
                    result+=((long)j)<<6*(decompStr.length()-1-i);  
                }  
            }  
        }  
        return result;  
    }     
    /** 
     *  
     * @param ch 
     * @return 
     */  
    private static long getCharIndexNum(char ch)  
    {  
        int num=((int)ch);  
        if(num>=48&&num<=57)  //0~9
        {  
            return num-48;  //0~9
        }  
        else if(num>=97&&num<=122)  //a~z
        {  
            return num-87;  //10~35
        }else if(num>=65&&num<=90)  //A~Z
        {  
            return num-29;  //36~61
        }
        else if(num==43)  //  +
        {  
            return 62;  //62
        }  
        else if (num == 45)  // -
        {  
            return 63;  //63
        }  
        return 0;  
    }  
     
  
} 